#include "SnowFlake.h"

int64_t NahidaProject::SnowFlake::GetCurrentTimeStamp() {
	auto now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
	return now;
}

int64_t NahidaProject::SnowFlake::WaitNextMillis(int64_t lastTimeStamp) {
	int64_t timeStamp;
	do {
		timeStamp = GetCurrentTimeStamp();
	} while (timeStamp <= lastTimeStamp);
	return timeStamp;
}

int64_t NahidaProject::SnowFlake::NextId() {
	std::lock_guard<std::mutex> lock(mutex);

	int64_t timeStamp = GetCurrentTimeStamp();

	if (timeStamp < lastTimeStamp) {
		throw std::runtime_error("Clock moved backwards. Refusing to generate id.");
	}

	if (timeStamp == lastTimeStamp) {
		sequence = (sequence + 1) & kMaxSequence;
		if (sequence == 0) {
			timeStamp = WaitNextMillis(lastTimeStamp);
		}
	}
	else {
		sequence = 0;
	}

	lastTimeStamp = timeStamp;

	int64_t id = ((timeStamp - kEpoch) << kTimestampShift) | (machineId << kMachineIdShift) | sequence;
	return id;
}
